
package jard.webshop.nbp;

import jard.webshop.util.FinancialException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

/**
 *
 * @author CJP
 */
@Entity
public class Invoice implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @ManyToOne
    @JoinColumn(nullable=false)
    private User customer;
    
    @JoinColumn(nullable=false)
    @OneToOne(mappedBy = "invoice")
    private Order order;
    
    private Boolean paid = false;
    
    @JoinColumn(nullable=false)
    @OneToMany(mappedBy = "invoice")
    private List<Payment> payments = new ArrayList<Payment>();
    
    @OneToMany(cascade=CascadeType.ALL)
    private List<InvoiceEntry> entries = new LinkedList<InvoiceEntry>();
    
    @Column(nullable=false)
    private Float totalAmount = 0f;
    
    @Column(nullable=false)
    private Float paidAmount = 0f;
    
    public Invoice() {
    }
    
    public Invoice(User user) {
        this.customer = user;
    }

    public Invoice(User user, Order order) {
        this.customer = user;
        this.order = order;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Invoice)) {
            return false;
        }
        Invoice other = (Invoice) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        String retVal = "";
        for(InvoiceEntry ie : entries) {
            retVal += "\n|" + ie.toString();
        }
        return "jard.webshop.nbp.Invoice[ id=" + id + ", " + paidAmount + "/" + totalAmount + "]" + retVal;
    }
    
    public String toPaymentString() {
        String retVal = "";
        for(Payment p : payments) {
            retVal += "\n|" + p.toString();
        }
        return "jard.webshop.nbp.Invoice[ id=" + id + ", " + paidAmount + "/" + totalAmount + "]" + retVal;
    }
    
    public Boolean isPaid() {
        return paid;
    }

    public void setPaid(Boolean paid) {
        this.paid = paid;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

    public List<Payment> getPayments() {
        return payments;
    }

    public void setPayments(List<Payment> payments) {
        this.payments = payments;
    }
    
    /**
     * This adds a payment to the invoice, setting the paidAmount and if the
     * invoice is paid in full, set the paid-field to True
     * 
     * @param payment
     * @throws FinancialException 
     */
    public void addPayment(Payment payment) throws FinancialException {
        Float paymentAmount = payment.getAmount();
        Float newPaidAmount = paidAmount + paymentAmount;
        if(newPaidAmount <= totalAmount) {
            payments.add(payment);
            paidAmount = newPaidAmount;
            if(paidAmount.equals(totalAmount)) {
                System.out.println("Setting " + this + " to paid=true");
                paid = true;
            } else {
                System.out.println("Invoice " + id + " not paid yet. " + paidAmount + "!=" + totalAmount);
            }
        } else {
            throw new FinancialException("Can't pay us more than we've charged.");
        }
    }

    public Float getTotalAmount() {
        return totalAmount;
    }

    public void setTotalAmount(Float totalAmount) {
        this.totalAmount = totalAmount;
    }

    public User getCustomer() {
        return customer;
    }

    public void setCustomer(User customer) {
        this.customer = customer;
    }

    public List<InvoiceEntry> getEntries() {
        return entries;
    }

    public void setEntries(List<InvoiceEntry> entries) {
        this.entries = entries;
    }
    
    public void addEntry(InvoiceEntry entry) {
        this.entries.add(entry);
        System.out.println("Invoice.addEntry where totalAmount => " + totalAmount);
        totalAmount += entry.getTotalCost();
    }

    public Float getPaidAmount() {
        return paidAmount;
    }

    public void setPaidAmount(Float paidAmount) {
        this.paidAmount = paidAmount;
    }
}
